package com.jp.bitmap;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;

import androidx.appcompat.app.AppCompatActivity;

/**
 * 一张图片被加载成 Bitmap 后实际占用内存是多大。
 * 通过 Options.inBitmap 可以实现 Bitmap 的复用，但是有一定的限制。
 * 当界面需要展示多张图片，尤其是在列表视图中，可以考虑使用 Bitmap 缓存。
 * 如果需要展示的图片过大，可以考虑使用分片加载的策略
 */
public class BitmapPoolActivity extends AppCompatActivity {


    private ImageView imageView;

    private Bitmap reuseBitmap;
    int resIndex;
    int[] resIds = {R.mipmap.load, R.mipmap.image};


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_bitmap_pool);
        imageView = findViewById(R.id.image);


        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inMutable = true;
        reuseBitmap = BitmapFactory.decodeResource(getResources(), resIds[0], options);
    }

    public void switchImage(View view) {
        imageView.setImageBitmap(getBitmap());
    }

    private Bitmap getBitmap() {
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        options.inSampleSize = 4;
        int index = resIndex++ % 2;
        BitmapFactory.decodeResource(getResources(), resIds[index], options);
        if (canUseForInBitmap(reuseBitmap, options)) {
            options.inMutable = true;//除了 inBitmap 参数之外，我还将 Options.inMutable 置为 true，这里如果不置为 true 的话，BitmapFactory 将不会重复利用 Bitmap 内存，
            options.inBitmap = reuseBitmap;
        }
        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeResource(getResources(), resIds[index], options);
    }


    static boolean canUseForInBitmap(
            Bitmap candidate, BitmapFactory.Options targetOptions) {

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            // From Android 4.4 (KitKat) onward we can re-use if the byte size of
            // the new bitmap is smaller than the reusable bitmap candidate
            // allocation byte count.
            int width = targetOptions.outWidth / Math.max(targetOptions.inSampleSize, 1);
            int height = targetOptions.outHeight / Math.max(targetOptions.inSampleSize, 1);
            int byteCount = width * height * getBytesPerPixel(candidate.getConfig());
            return byteCount <= candidate.getAllocationByteCount();
        }

        // On earlier versions, the dimensions must match exactly and the inSampleSize must be 1
        return candidate.getWidth() == targetOptions.outWidth
                && candidate.getHeight() == targetOptions.outHeight
                && targetOptions.inSampleSize == 1;
    }

    /**
     * A helper function to return the byte usage per pixel of a bitmap based on its configuration.
     */
    static int getBytesPerPixel(Bitmap.Config config) {
        if (config == Bitmap.Config.ARGB_8888) {
            return 4;
        } else if (config == Bitmap.Config.RGB_565) {
            return 2;
        } else if (config == Bitmap.Config.ARGB_4444) {
            return 2;
        } else if (config == Bitmap.Config.ALPHA_8) {
            return 1;
        }
        return 1;
    }

}